package com.kstudio.ksnapshot.kedit;

import java.io.IOException;

import android.content.Context;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnCompletionListener;
import android.media.MediaPlayer.OnErrorListener;
import android.media.MediaPlayer.OnPreparedListener;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.AttributeSet;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.widget.ProgressBar;

import com.kstudio.ksnapshot.KUtil;

public class KEditVideoPlayer extends SurfaceView implements SurfaceHolder.Callback, OnCompletionListener, OnErrorListener, OnPreparedListener {
  private KUtil KLog = new KUtil("KEditVideoPlayer");

  private MediaPlayer mMediaPlayer;
  private KEditVideoPlayerListener mListener;
  private Context mContext;
  private SurfaceHolder mSurfaceHolder;

  private String mVideoPath;
  private int mSeekWhenPrepared;

  private int mVideoWidth;
  private int mVideoHeight;

  private KVideoState mKVideoState;

  private enum KVideoState {
      STATE_ERROR,
      STATE_IDLE,
      STATE_PREPARING,
      STATE_PREPARED,
      STATE_PLAYING,
      STATE_PAUSED
  }

  public interface KEditVideoPlayerListener {
      void onKEditVideoPlayerActive();
      void onKEditVideoPlayerError();
      void onKEditVideoPlayerDuration(int duration);
  }

  public KEditVideoPlayer(Context context) {
      this(context, null);
  }

  public KEditVideoPlayer(Context context, AttributeSet attrs) {
      this(context, attrs , 0);
  }

  public KEditVideoPlayer(Context context, AttributeSet attrs, int defStyle) {
      super(context, attrs, defStyle);

      this.getHolder().addCallback(this);

      mContext = context;
      mVideoPath = null;
      mSeekWhenPrepared = 0;
      mMediaPlayer = null;
      mSurfaceHolder = null;
      mKVideoState = KVideoState.STATE_IDLE;
  }

  @Override
  protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
      int width = getDefaultSize(mVideoWidth, widthMeasureSpec);
      int height = getDefaultSize(mVideoHeight, heightMeasureSpec);

      if (mVideoWidth > 0 && mVideoHeight > 0) {
          if ( mVideoWidth * height  > width * mVideoHeight ) {
              height = width * mVideoHeight / mVideoWidth;
              KLog.i("F : onMeasure 1 width = %d , height = %d", width, height);
          } else if ( mVideoWidth * height  < width * mVideoHeight ) {
              width = height * mVideoWidth / mVideoHeight;
              KLog.i("F : onMeasure 2 width = %d , height = %d", width, height);
          } else {
              KLog.i("F : onMeasure 3 width = %d , height = %d", width, height);
          }
      } else {
          KLog.i("F : onMeasure 4 width = %d , height = %d", width, height);
      }
      setMeasuredDimension(width, height);
  }

  @Override
  public void surfaceCreated(SurfaceHolder holder) {
      KLog.i("F : surfaceCreated");

      mSurfaceHolder = holder;
      Kopen();
  }

  @Override
  public void surfaceChanged(SurfaceHolder holder, int format, int width,
          int height) {
      KLog.i("F : surfaceChanged");
  }

  @Override
  public void surfaceDestroyed(SurfaceHolder holder) {
      KLog.i("F : surfaceDestroyed");

      mSurfaceHolder = null;
      Krelease();
  }

  static class KSavedState extends BaseSavedState {
      int seekTime;

      /**
       * Constructor called from {@link ProgressBar#onSaveInstanceState()}
       */
      KSavedState(Parcelable superState) {
          super(superState);
      }

      /**
       * Constructor called from {@link #CREATOR}
       */
      private KSavedState(Parcel in) {
          super(in);
          seekTime = in.readInt();
      }

      @Override
      public void writeToParcel(Parcel out, int flags) {
          super.writeToParcel(out, flags);
          out.writeInt(seekTime);
      }

      public static final Parcelable.Creator<KSavedState> CREATOR
              = new Parcelable.Creator<KSavedState>() {
          public KSavedState createFromParcel(Parcel in) {
              return new KSavedState(in);
          }

          public KSavedState[] newArray(int size) {
              return new KSavedState[size];
          }
      };
  }

  @Override
  protected Parcelable onSaveInstanceState() {
      Parcelable superState = super.onSaveInstanceState();
      KSavedState ss = new KSavedState(superState);

      if(mMediaPlayer != null) {
          ss.seekTime = mMediaPlayer.getCurrentPosition();
      }
      return ss;
  }

  @Override
  protected void onRestoreInstanceState(Parcelable state) {
      KSavedState ss = (KSavedState) state;
      super.onRestoreInstanceState(ss.getSuperState());

      mSeekWhenPrepared = ss.seekTime;
  }

  @Override
  public boolean onError(MediaPlayer mp, int what, int extra) {
      KLog.i("F : onError");

      if(mListener != null) mListener.onKEditVideoPlayerError();
      return false;
  }

  @Override
  public void onCompletion(MediaPlayer mp) {
      KLog.i("F : onCompletion");
  }

  @Override
  public void onPrepared(MediaPlayer mp) {
      KLog.i("F : onPrepared");

      KSetDuration(mp.getDuration());
      mKVideoState = KVideoState.STATE_PREPARED;

      mVideoWidth = mp.getVideoWidth();
      mVideoHeight = mp.getVideoHeight();

      int seekToPosition = mSeekWhenPrepared;
      if (seekToPosition >= 0) {
          KseekTo(seekToPosition);
      }

      if (mVideoWidth != 0 && mVideoHeight != 0) {
          getHolder().setFixedSize(mVideoWidth, mVideoHeight);
      }
  }

  public void setVideoPath(String videoPath) {
      KLog.i("F : setVideoPath");

      mVideoPath = videoPath;
      Kopen();
  }

  private void Kopen() {
      if(mVideoPath == null || mSurfaceHolder == null) {
          return;
      }
      KLog.i("F : Kopen");

      // Tell the music playback service to pause
      // TODO: these constants need to be published somewhere in the framework.
//      Intent i = new Intent("com.android.music.musicservicecommand");
//      i.putExtra("command", "pause");
//      mContext.sendBroadcast(i);

      Krelease();
      try {
          mMediaPlayer = new MediaPlayer();
          mMediaPlayer.setOnPreparedListener(this);
//          mMediaPlayer.setOnVideoSizeChangedListener(mSizeChangedListener);
//          mDuration = -1;
          mMediaPlayer.setOnCompletionListener(this);
          mMediaPlayer.setOnErrorListener(this);
//          mMediaPlayer.setOnInfoListener(mOnInfoListener);
//          mMediaPlayer.setOnBufferingUpdateListener(mBufferingUpdateListener);
//          mCurrentBufferPercentage = 0;
          mMediaPlayer.setDataSource(mVideoPath);
          mMediaPlayer.setDisplay(mSurfaceHolder);
          mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
          mMediaPlayer.setScreenOnWhilePlaying(true);
          mMediaPlayer.prepareAsync();

          mKVideoState = KVideoState.STATE_PREPARING;
      } catch (IllegalArgumentException e) {
          if(mListener != null) mListener.onKEditVideoPlayerError();
          e.printStackTrace();
      } catch (SecurityException e) {
          if(mListener != null) mListener.onKEditVideoPlayerError();
          e.printStackTrace();
      } catch (IllegalStateException e) {
          if(mListener != null) mListener.onKEditVideoPlayerError();
          e.printStackTrace();
      } catch (IOException e) {
          if(mListener != null) mListener.onKEditVideoPlayerError();
          e.printStackTrace();
      }
  }

  public void Krelease() {
      KLog.i("F : Krelease");

      if (mMediaPlayer != null)
      {
          mMediaPlayer.reset();
          mMediaPlayer.stop();
          mMediaPlayer.release();
          mMediaPlayer = null;
      }
      mKVideoState = KVideoState.STATE_IDLE;
  }

  public void KseekTo(int msec) {
      KLog.i("F : KseekTo");

      if(KisInPlaybackState()) {
          mMediaPlayer.seekTo(msec);
          mSeekWhenPrepared = -1;
      } else {
          mSeekWhenPrepared = msec;
      }
  }

  public int KGetDuration() {
      int duration = 0;
      
      if (mMediaPlayer != null) {
          mMediaPlayer.getDuration();
      }
      
      return duration;
  }
  
  private boolean KisInPlaybackState() {
      KLog.i("F : KisInPlaybackState");

      return (mMediaPlayer != null &&
              mKVideoState != KVideoState.STATE_ERROR &&
              mKVideoState != KVideoState.STATE_IDLE &&
              mKVideoState != KVideoState.STATE_PREPARING);
  }
  
  public int KgetCurrentTime() {
      if(KisInPlaybackState()) {
          int cTime = mMediaPlayer.getCurrentPosition();
          KLog.i("F : KgetCurrentTime = %d",cTime);
          return cTime;
      }
      KLog.e("F : KgetCurrentTime not Playing state");
      return 0;
  }
  
  private void KSetDuration(int duration) {
      if(mListener != null) mListener.onKEditVideoPlayerDuration(duration);
  }
  
  public void setVideoPlayerListener(KEditVideoPlayerListener listener) {
      mListener = listener;
  }
}